﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace NLite.Domain.Model
{
    /// <summary>
    /// 实体标志接口
    /// </summary>
    public interface IEntity
    {
    }

    /// <summary>
    /// 实体接口
    /// </summary>
    /// <typeparam name="TId"></typeparam>
    public interface IEntity<TId> : IEntity
    {
        /// <summary>
        /// 得到或设置实体Id
        /// </summary>
        TId Id { get; set; }
    }

    /// <summary>
    /// 实体基类
    /// </summary>
    /// <typeparam name="TId"></typeparam>
    [Serializable]
    public abstract class Entity<TId> : IEntity<TId>
    {
        /// <summary>
        /// 标识Id
        /// </summary>
        public virtual TId Id { get; set; }

        /// <summary>
        /// 版本
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public virtual int Version { get; set; }

        /// <summary>
        /// 重定Equals，判定两个实体是否相等
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override bool Equals(object obj)
        {
            return Equals(obj as Entity<TId>);
        }

        /// <summary>
        /// 判定一个实体是否与另一个实体相等
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public virtual bool Equals(Entity<TId> other)
        {
            if (other == null)
                return false;

            if (ReferenceEquals(this, other))
                return true;

            if (!IsTransient(this) &&
                !IsTransient(other) &&
                Equals(Id, other.Id))
            {
                var otherType = other.GetUnproxiedType();
                var thisType = GetUnproxiedType();
                return thisType.IsAssignableFrom(otherType) ||
                       otherType.IsAssignableFrom(thisType);
            }

            return false;
        }

        /// <summary>
        /// 重定HashCode方法
        /// </summary>
        /// <returns></returns>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override int GetHashCode()
        {
            if (Equals(Id, default(TId)))
                return base.GetHashCode();
            return Id.GetHashCode();
        }

        /// <summary>
        /// 判定一个对实体是不是瞬态对象
        /// </summary>
        /// <param name="obj">判定对象</param>
        /// <returns></returns>
        private bool IsTransient(Entity<TId> obj)
        {
            return obj != null &&
                   Equals(obj.Id, default(TId));
        }

        /// <summary>
        /// 取得原生类型
        /// </summary>
        /// <returns></returns>
        private Type GetUnproxiedType()
        {
            return GetType();
        }

    }

    /// <summary>
    /// 实体基类
    /// </summary>
    [Serializable]
    public class Entity : Entity<long> { }
}
